package Engine.Game;

import Engine.Character.OverworldCharacter;
import Engine.Scene.BattleManager;
import Engine.Scene.Map;
import Main.Tuxedo;
import java.io.IOException;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;

/**
 * Controls display related routines. The class handles Graphics-related subroutines and owns screen sizes references and every static image.
 * The currently displayed screen is painted within the class. Pause and Status screens are fully handled by the class. Overworld and Battle
 * screens are requested to be painted out of the class, to prevent sending other object references than the Graphics object.
 * @author Chronicles of Tuxedo dev team
 */
public class GameDisplay extends GameCanvas {

    //--------------------------------------------------
    //GameDisplay general variables---------------------
    private static int screenHeight, screenWidth;
    private final int horizontalAnchor, verticalAnchor;
    private int currentCharacterCode;
    private int keyStates;
    private int pastKeyStates;
    private Image[] menuImages;
    private Image[] battleImages;
    private Image overworldImage;
    private Image mainPlayerImage;
    private Image secondPlayerImage;
    private Font fontStatus;
    private Font fontBattle;
    private int currentScreen;
    private int currentOption;
    private int playerCode;
    private int secondPlayerCode;
    private int heightCursor;
    private int heightStop;
    private boolean goingDown;
    private boolean moving;
    private boolean defaultLanguage;
    private boolean isGameOver;
    private Image miniMap;
    //Object references---------------------------------
    private Graphics g;
    private GameMotion motion;
    private Tuxedo midlet;
    private GameAdmin adminGame;
    private OverworldCharacter mainPlayer;
    private OverworldCharacter secondPlayer;
    private BattleManager battleScene;
    //Screen sizes constants----------------------------
    //Screen center
    private final int SCREEN_X_CENTER;
    private final int SCREEN_Y_CENTER;
    //Quarter divisions (Status menu)
    private final int SCREEN_X_FIRST_QUARTER;
    private final int SCREEN_X_SECOND_QUARTER;
    private final int SCREEN_X_THIRD_QUARTER;
    private final int SCREEN_Y_FIRST_QUARTER;
    private final int SCREEN_Y_SECOND_QUARTER;
    private final int SCREEN_Y_THIRD_QUARTER;
    //Fifth divisions (Battle screen)
    private final int SCREEN_X_FIRST_FIFTH;
    private final int SCREEN_X_SECOND_FIFTH;
    private final int SCREEN_X_THIRD_FIFTH;
    private final int SCREEN_X_FOURTH_FIFTH;
    private final int SCREEN_X_FIFTH_FIFTH;
    //Player's anchors
    private int playerXAnchor;
    private int playerYAnchor;
    //Enemies' anchors
    private int enemyXAnchor;
    private int enemyYAnchor;
    //Status menu information---------------------------
    private int playerHP;
    private int playerMaxHP;
    private int playerMP;
    private int playerMaxMP;
    private int playerXP;
    private int playerLevel;
    private String playerHPLabel;
    private String playerMPLabel;
    private String playerXPLabel;
    private String playerLevelLabel;
    //Bar sizes------------------------------------------
    private int barHPWidth;
    private int barMPWidth;
    private int barXPWidth;
    private byte[] data;
    private String dataString = "";
    private static final String levelLabel = "Level";
    private static final String LYN_LABEL = "Lyn";
    private static final String ELIWOOD_LABEL = "Eliwood";
    private static final String EIRIK_LABEL = "Eirik";
    //Screen type constants-----------------------------
    private final int OVERWORLD_SCREEN = 0;
    private final int BATTLE_SCREEN = 1;
    private final int STATUS_SCREEN = 2;
    private final int PAUSE_SCREEN = 3;
    private final int PAUSE_OPTIONS = 3;
    //Cursor constants----------------------------------
    private final int CURSOR_X_ANCHOR;
    private final int CURSOR_Y_ANCHOR;
    private int CURSOR_MOVEMENT = 20;
    /**
     * The height of the status bar
     */
    public static final int BAR_HEIGHT = 10;
    //--------------------------------------------------
    /**
     * Hexadecimal code representing the white color
     */
    public static final int WHITE = 0xFFFFFF;
    /**
     * Hexadecimal code representing the black color
     */
    public static final int BLACK = 0x000000;
    /**
     * Hexadecimal code representing the green color
     */
    public static final int GREEN = 0x00FF00;
    /**
     * Hexadecimal code representing the yellow color
     */
    public static final int YELLOW = 0xFFFF00;
    /**
     * Hexadecimal code representing the red color
     */
    public static final int RED = 0xFF0000;
    /**
     * Hexadecimal code representing the blue color
     */
    public static final int BLUE = 0x0000FF;
    //--------------------------------------------------

    /**
     * Creates a GameCanvas object that fully handles the screen and sets every screen reference in order to paint the screen correctly in every
     * device possible.
     * @param midlet Reference to the container MIDlet
     * @param character MainPlayer integer index constant representing a user's character, passed from the MIDlet when starting a new game or
     * loading from a file.
     */
    public GameDisplay(Tuxedo midlet, int character, boolean isNewGame, String characterData, boolean language, char difficulty) {
        super(true);
        //Start loading screen
        //GameDisplay references
        this.defaultLanguage = language;
        this.midlet = midlet;
        g = this.getGraphics();
        this.setFullScreenMode(true);
        menuImages = new Image[8];
        battleImages = new Image[6];
        this.currentCharacterCode = character;
        //Screen initialization
        screenHeight = this.getHeight();
        screenWidth = this.getWidth();
        //Center
        SCREEN_X_CENTER = screenWidth / 2;
        SCREEN_Y_CENTER = screenHeight / 2;
        //Quarters (Status screen)
        SCREEN_X_FIRST_QUARTER = screenWidth / 4;
        SCREEN_X_SECOND_QUARTER = SCREEN_X_FIRST_QUARTER + (screenWidth / 4);
        SCREEN_X_THIRD_QUARTER = SCREEN_X_SECOND_QUARTER + (screenWidth / 4);
        SCREEN_Y_FIRST_QUARTER = screenHeight / 4;
        SCREEN_Y_SECOND_QUARTER = SCREEN_Y_FIRST_QUARTER + (screenHeight / 4);
        SCREEN_Y_THIRD_QUARTER = SCREEN_Y_SECOND_QUARTER + (screenHeight / 4);
        //Fifths (Battle screen)
        SCREEN_X_FIRST_FIFTH = screenWidth / 5;
        SCREEN_X_SECOND_FIFTH = SCREEN_X_FIRST_FIFTH + (screenWidth / 5);
        SCREEN_X_THIRD_FIFTH = SCREEN_X_SECOND_FIFTH + (screenWidth / 5);
        SCREEN_X_FOURTH_FIFTH = SCREEN_X_THIRD_FIFTH + (screenWidth / 5);
        SCREEN_X_FIFTH_FIFTH = SCREEN_X_FOURTH_FIFTH + (screenWidth / 5);
        //Constant check-up lines. Can be safely deleted
        /*
        System.out.println("Screen center. X: " + SCREEN_X_CENTER + " Y: " + SCREEN_Y_CENTER);
        System.out.println("Quarter references (X). 1: " + SCREEN_X_FIRST_QUARTER + " 2: " + SCREEN_X_SECOND_QUARTER + " 3: " + SCREEN_X_THIRD_QUARTER + " Screen's end: " + screenWidth);
        System.out.println("Quarter references (Y). 1: " + SCREEN_Y_FIRST_QUARTER + " 2: " + SCREEN_Y_SECOND_QUARTER + " 3: " + SCREEN_Y_THIRD_QUARTER + " Screen's end: " + screenHeight);
        System.out.println("Fifth references. 1: " + SCREEN_X_FIRST_FIFTH + " 2: " + SCREEN_X_SECOND_FIFTH + " 3: " + SCREEN_X_THIRD_FIFTH + " 4: " + SCREEN_X_FOURTH_FIFTH +  " Screen's end: " + screenWidth);
        */
        if (screenWidth < 320) {
            horizontalAnchor = (320 - screenWidth) / 2;
        } else {
            horizontalAnchor = 0;
        }
        if (screenHeight < 320) {
            verticalAnchor = (320 - screenHeight) / 2;
        } else {
            verticalAnchor = 0;
        }
        loadStandardImages();
        fontStatus = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_SMALL);
        fontBattle = Font.getFont(Font.FONT_STATIC_TEXT, Font.STYLE_PLAIN, Font.SIZE_SMALL);
        //Screen inicialized
        CURSOR_X_ANCHOR = SCREEN_X_CENTER - (menuImages[2].getWidth() / 2);
        CURSOR_Y_ANCHOR = SCREEN_Y_CENTER - (menuImages[2].getHeight() / 2);
        pastKeyStates = 0;
        currentOption = 0;
        currentScreen = OVERWORLD_SCREEN;
        data = new byte[512];
        adminGame = new GameAdmin(screenWidth, screenHeight, character, this, isNewGame, characterData, difficulty);
        mainPlayer = adminGame.getPlayer();
        this.getCharacterStats();
        playerXPLabel = "XP: " + playerXP;
        motion = new GameMotion(this);
        motion.play();
    }

    private void loadStandardImages() {
        try {
            menuImages[0] = Image.createImage(Image.createImage("/Images/UserInterface/Background.png"), horizontalAnchor, verticalAnchor, screenWidth, screenHeight, Sprite.TRANS_NONE);
            menuImages[1] = Image.createImage("/Images/UserInterface/Cursor.png");
            if(defaultLanguage) {
                menuImages[2] = Image.createImage("/Images/UserInterface/PauseOptions-en.png");
            } else {
                menuImages[2] = Image.createImage("/Images/UserInterface/PauseOptions-es.png");
            }
            menuImages[3] = Image.createImage("/Images/Players/lyn.png");
            menuImages[4] = Image.createImage("/Images/Players/eliwood.png");
            menuImages[5] = Image.createImage("/Images/Players/eirik.png");
            menuImages[6] = Image.createImage(Image.createImage("/Images/UserInterface/Transparent.png"), 0, 0, screenWidth, screenHeight, Sprite.TRANS_NONE);
            menuImages[7] = Image.createImage("/Images/UserInterface/GameOver.png");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public Graphics getG() {
        return g;
    }

    //<<------------------------------------------Keyboard handler methods------------------------------------------>>

    /**
     * Reads the keyboard, according to the currentScreen variable that the user is currently visualizing, stored at GameAdmin.
     */
    public void handleKeyboard() {
        keyStates = this.getKeyStates();
        switch(currentScreen) {
            case OVERWORLD_SCREEN:
                this.handleOverworldKeyboard();
                break;
            case BATTLE_SCREEN:
                battleScene.battleCycle();
                break;
            case STATUS_SCREEN:
                this.calculateBarWidth(false);
                this.getCharacterStats();
                this.handleStatusKeyboard();
                break;
            case PAUSE_SCREEN:
                this.handlePauseKeyboard();
                break;
        }
    }

    /**
     * Handles the keyboard event when the user is playing at the map. The method delegates the action movement to GameAdmin, where it's passed
     * to the variable mainPlayer, the user's character. Each time the user moves, the method calls the method step() at GameAdmin, in order to
     * calculate the number of steps left to start a battle.
     * @see step()
     */
    public void handleOverworldKeyboard() {
        if(keyStates != 0) {
                if ((keyStates & UP_PRESSED) != 0) {
                    adminGame.movePlayer(GameAdmin.DIRECTION_UP);
                } else if ((keyStates & DOWN_PRESSED) != 0) {
                    adminGame.movePlayer(GameAdmin.DIRECTION_DOWN);
                } else if ((keyStates & LEFT_PRESSED) != 0) {
                    adminGame.movePlayer(GameAdmin.DIRECTION_LEFT);
                } else if ((keyStates & RIGHT_PRESSED) != 0) {
                    adminGame.movePlayer(GameAdmin.DIRECTION_RIGHT);
                } else if ((keyStates & FIRE_PRESSED) != 0) {
                    this.handleOverworldClick();
                } else if ((keyStates & GAME_A_PRESSED) != 0) {
                    currentScreen = PAUSE_SCREEN;
                } else if ((keyStates & GAME_B_PRESSED) != 0) {
                    currentScreen = STATUS_SCREEN;
                } else if ((keyStates & FIRE_PRESSED) != 0) {

                }
            }
            else {
                adminGame.movePlayer(GameAdmin.DIRECTION_STAND);
            }
    }

    /**
     * Gets the information of the main player and then calls the midlet to write the data on a specified file.
     * @param currentScene the current scene where the player is
     * @param fileNumber the file where the user wants to save
     */
    public void saveGame(int fileNumber) {
        dataString = this.adminGame.getCurrentScene() + "."+mainPlayer.getCharacterCode()+"."+playerHP + "." + playerMP + "." + playerXP + "." + this.mainPlayer.getCurrentLevel() + "." + this.mainPlayer.getX() + "." + this.mainPlayer.getY();
        data = dataString.getBytes();
        midlet.writeData(data, fileNumber);
    }

    public void resumeMusic() {
        adminGame.resumeMusic();
    }

    public void toggleMusic() {
        adminGame.toggleMusic();
    }
    
    /**
     * Handles the keyboard event when the user is playing a battle. The method delegates the taken action from the cross menu to GameAdmin,
     * where it's passed to the corresponding BattleManager to execute the current battle cycle. While animations are taking place, the method 
     * ignores any input.
     */
    public void handleBattleKeyboard() {
        if ((keyStates & LEFT_PRESSED) != 0) {
            if (keyStates != pastKeyStates) {
                pastKeyStates = keyStates;
                battleScene.leftCrossSelection();
            }
        } else if ((keyStates & UP_PRESSED) != 0) {
            if (keyStates != pastKeyStates) {
                pastKeyStates = keyStates;
                battleScene.upCrossSelection();
            }
        } else if ((keyStates & RIGHT_PRESSED) != 0) {
            if (keyStates != pastKeyStates) {
                pastKeyStates = keyStates;
                battleScene.rightCrossSelection();
            }
        } else if ((keyStates & DOWN_PRESSED) != 0) {
            if (keyStates != pastKeyStates) {
                pastKeyStates = keyStates;
                battleScene.downCrossSelection();
            }
        } else if ((keyStates & FIRE_PRESSED) != 0) {
            if (keyStates != pastKeyStates) {
                pastKeyStates = keyStates;
                battleScene.handleClick();
            }
        } else if ((keyStates & GAME_B_PRESSED) != 0) {
            if (keyStates != pastKeyStates) {
                pastKeyStates = keyStates;
                this.finishBattle();
            }
        } else if ((keyStates & GAME_D_PRESSED) != 0) {
            if (keyStates != pastKeyStates) {
                pastKeyStates = keyStates;
                battleScene.backSelection();
            }
        } else {
            pastKeyStates = 0;
        }
    }

    /**
     * Handles the keyboard event when the user asks to display the status menu.
     */
    public void handleStatusKeyboard() {
        if ((keyStates & GAME_B_PRESSED) != 0) {
            if ( keyStates != pastKeyStates ) {
                pastKeyStates = keyStates;
                this.handleStatusClick();
            }
        } else {
            pastKeyStates = 0;
        }
    }

    /**
     * Handles the keyboard event when the user asks to display the pause menu. The method decides wether it should continue, display the game's
     * options or terminate the application.
     */
    public void handlePauseKeyboard() {
        if ( !moving ) {
            if ((keyStates & DOWN_PRESSED) != 0) {
                if (keyStates != pastKeyStates) {
                    pastKeyStates = keyStates;
                    if (currentOption < PAUSE_OPTIONS - 1) {
                        heightCursor = CURSOR_Y_ANCHOR + (this.currentOption * CURSOR_MOVEMENT);
                        this.goingDown = true;
                        this.moving = true;
                    } else if (currentOption == PAUSE_OPTIONS - 1) {
                        currentOption = 0;
                        this.moving = false;
                    }
                }
            } else if (((keyStates & FIRE_PRESSED) != 0) || ((keyStates & RIGHT_PRESSED) != 0)) {
                if (keyStates != pastKeyStates) {
                    pastKeyStates = keyStates;
                    this.handlePauseClick();
                }
            } else if ((keyStates & UP_PRESSED) != 0) {
                if (keyStates != pastKeyStates) {
                    pastKeyStates = keyStates;
                    if (currentOption > 0) {
                        heightCursor = CURSOR_Y_ANCHOR + (this.currentOption * CURSOR_MOVEMENT);
                        this.goingDown = false;
                        this.moving = true;
                    } else if (currentOption == 0) {
                        currentOption = PAUSE_OPTIONS - 1;
                        this.moving = false;
                    }
                }

            }  else if ((keyStates & GAME_B_PRESSED) != 0) {
                if (keyStates != pastKeyStates) {
                    currentScreen = STATUS_SCREEN;
                }
            } else {
                pastKeyStates = 0;
            }
        }
    }

    /**
     * Handles a click event signaled in any menu.
     */
    public void handleClick() {
        switch(currentScreen) {
            case PAUSE_SCREEN:
                this.handlePauseClick();
                break;
            case STATUS_SCREEN:
                this.handleStatusClick();
                break;
        }
    }

    /**
     * Handles the interaction in the overworld map
     */
    public void handleOverworldClick() {
        //Interaction within the map.
        System.out.println("Working.");
        if ( isGameOver ) {
            this.midlet.shutDownApp(true);
        }
    }

    /**
     * Handles a click event inside a pause menu. If the first option is chosen, the game continues normally. If the second option is chosen,
     * the options menu is displayed. If the third option is chosen, the application is terminated.
     */
    public void handlePauseClick() {
        /*
         * REFACTOR COMMENTS
         * case 0: Continue the game. (Done)
         * case 1: Pop options menu. Not implemented.
         * case 2: Call the MIDlet's shutdown and terminate the application. (Halfly done)
         */
        switch (currentOption) {
            case 0:
                currentScreen = OVERWORLD_SCREEN;
                break;
            case 1:
                this.saveGame(Tuxedo.FILE_ONE);
                break;
            case 2:
                this.adminGame.shutDownMusic();
                midlet.shutDownApp(true);
                break;
            default:
                break;
        }
    }

    /**
     * Handles a click event inside a status menu.
     */
    public void handleStatusClick() {
        currentScreen = OVERWORLD_SCREEN;
    }

    //<<------------------------------------------------------------------------------------------------------------>>
    //<<------------------------------------------Battle Graphics Methods------------------------------------------>>

    /**
     * Executes the corresponding routine related to graphics when a battle starts. Images are loaded and the screen is set to the Battle
     * screen until the BattleManager signalizes that the battle has ended.
     */
    public void startBattle() {
        //Display loading screen
        loadBattleImages();
        calculateBarWidth(true);
        //Terminate loading screen
        currentScreen = BATTLE_SCREEN;
    }

    /**
     * Executes the corresponding routine related to graphics when a battle starts. Images are destroyed and the screen is set back to the
     * Overwrold screen.
     */
    public void finishBattle() {
        currentScreen = OVERWORLD_SCREEN;
        //Deallocate images
        battleImages[0] = null;
        battleImages[1] = null;
        battleImages[2] = null;
        battleScene.finishBattle();
    }

    /**
     * Chooses the corresponding battle image for the current scene where the player is, stored in the variable currentScene at GameAdmin to
     * choose the battle scene's image.
     */
    public Image loadBattleImageBackground() throws IOException {
        Image fullImage;
            switch (adminGame.getCurrentScene()) {
                case Map.FISHBOWL:
                    fullImage = Image.createImage("/Images/Battle/Fishbowl-Battle.png");
                    break;
                case Map.OUTER_FISHBOWL:
                    fullImage = Image.createImage("/Images/Battle/OuterFishbowl-Battle.png");
                    break;
                case Map.DISTILLERY:
                    fullImage = Image.createImage("/Images/Battle/Distillery-Battle.png");
                    break;
                case Map.OUTER_DISTILLERY:
                    fullImage = Image.createImage("/Images/Battle/OuterDistillery-Battle.png");
                    break;
                case Map.OUTSIDES:
                    fullImage = Image.createImage("/Images/Battle/Outsides-Battle.png");
                    break;
                case Map.WOLVES_UPPER_LEFT:
                    fullImage = Image.createImage("/Images/Battle/Wolves-Battle.png");
                    break;
                case Map.WOLVES_UPPER_RIGHT:
                    fullImage = Image.createImage("/Images/Battle/Wolves-Battle.png");
                    break;
                case Map.WOLVES_LOWER_LEFT:
                    fullImage = Image.createImage("/Images/Battle/Wolves-Battle.png");
                    break;
                case Map.WOLVES_LOWER_RIGHT:
                    fullImage = Image.createImage("/Images/Battle/Wolves-Battle.png");
                    break;
                case Map.TREES_ZONE_1:
                    fullImage = Image.createImage("/Images/Battle/TreesZone1-Battle.png");
                    break;
                case Map.TREES_ZONE_2:
                    fullImage = Image.createImage("/Images/Battle/TreesZone2-Battle.png");
                    break;
                case Map.TREES_ZONE_3:
                    fullImage = Image.createImage("/Images/Battle/TreesZone3-Battle.png");
                    break;
                case Map.CCI_RECEIVER:
                    fullImage = Image.createImage("/Images/Battle/CCI-Battle.png");
                    break;
                case Map.CCI_COMPUTERS:
                    fullImage = Image.createImage("/Images/Battle/CCI-Battle.png");
                    break;
                default:
                    System.out.println("Image code error.");
                    fullImage = null;
            }
            return Image.createImage(fullImage, horizontalAnchor, 0, screenWidth, screenHeight, Sprite.TRANS_NONE);
    }

    /**
     * Loads the battle images required when a battle starts.
     */
    public void loadBattleImages() {
        try {
            battleImages[0] = this.loadBattleImageBackground();
            battleImages[1] = Image.createImage(Image.createImage("/Images/Battle/Pane.png"), 0, 0, screenWidth, 20, Sprite.TRANS_NONE);
            if (defaultLanguage) {
                battleImages[2] = Image.createImage("/Images/Battle/Cross-en.png");
                battleImages[3] = Image.createImage("/Images/Battle/Cross-Item-en.png");
                battleImages[4] = Image.createImage("/Images/Battle/Cross-Magic-en.png");
            } else {
                battleImages[2] = Image.createImage("/Images/Battle/Cross-es.png");
                battleImages[3] = Image.createImage("/Images/Battle/Cross-Item-es.png");
                battleImages[4] = Image.createImage("/Images/Battle/Cross-Magic-es.png");
            }
            battleImages[5] = Image.createImage("/Images/Battle/Target.png");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Gets the third quarter of the screen
     * @return the third quarter of the screen
     */
    public int getSCREEN_Y_THIRD_QUARTER() {
        return SCREEN_Y_THIRD_QUARTER;
    }

    //<<------------------------------------------------------------------------------------------------------------>>
    //<<-----------------------------------------------Paint methods------------------------------------------------>>

    /**
     * Switches between the screens and paint the in-game objects
     */
    public void paint() {
        g.setColor(0x000000);
        g.fillRect(0, 0, screenWidth, screenHeight);
        switch(currentScreen) {
            case OVERWORLD_SCREEN:
                adminGame.paint(g);
                if ( isGameOver ) {
                    this.paintGameOver();
                }
                break;
            case BATTLE_SCREEN:
                paintBattleScreen();
                break;
            case STATUS_SCREEN:
                adminGame.paint(g);
                paintStatusScreen(STATUS_SCREEN);
                break;
            case PAUSE_SCREEN:
                adminGame.paint(g);
                paintPauseMenu();
                break;
        }
        this.flushGraphics();
    }

    //Paints the pause menu
    private void paintPauseMenu() {
        heightStop = CURSOR_Y_ANCHOR + (this.currentOption * CURSOR_MOVEMENT);
        if ( moving ) {
            if ( goingDown ) {
                heightCursor+=2;
                if ( heightCursor == heightStop + CURSOR_MOVEMENT) {
                    this.currentOption++;
                    moving = false;
                }
            } else {
                heightCursor-=2;
                if ( heightCursor == heightStop - CURSOR_MOVEMENT) {
                    this.currentOption--;
                    moving = false;
                }
            }
        } else {
            this.heightCursor = heightStop;
        }
        g.drawImage(menuImages[6], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.VCENTER | Graphics.HCENTER);
        g.drawImage(menuImages[0], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.VCENTER | Graphics.HCENTER);
        g.drawImage(menuImages[1], CURSOR_X_ANCHOR, heightCursor, Graphics.TOP | Graphics.RIGHT);
        g.drawImage(menuImages[2], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.HCENTER | Graphics.VCENTER);
    }

    //Paints the status screen of the battle and the cross
    private void paintBattleScreen() {
        g.drawImage(battleImages[0], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.VCENTER | Graphics.HCENTER);
        g.drawImage(battleImages[1], SCREEN_X_CENTER, 0, Graphics.HCENTER | Graphics.TOP);
        this.paintStatusScreen(this.BATTLE_SCREEN);
        battleScene.paint();
        if (battleScene.checkBattleStatus() == BattleManager.ACTIVE_PLAYER_TURN) {
            switch(battleScene.getCurrentCrossSelection()) {
                case BattleManager.CROSS_MAIN:
                    g.drawImage(battleImages[2], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.BOTTOM | Graphics.HCENTER);
                    break;
                case BattleManager.CROSS_ITEM:
                    g.drawImage(battleImages[3], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.BOTTOM | Graphics.HCENTER);
                    break;
                case BattleManager.CROSS_MAGIC:
                    g.drawImage(battleImages[4], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.BOTTOM | Graphics.HCENTER);
                    break;
                case BattleManager.CROSS_TARGET:
                    battleScene.paintTarget(battleImages[5]);
                    break;
            }
        }
        
    }

    //<<------------------------------------------------------------------------------------------------------------>>

    /**
     * Sets the current battle manager
     * @param currentBattleScene the current battle manager
     */
    public void setManager(BattleManager currentBattleScene) {
        this.battleScene = currentBattleScene;
    }

    //<<------------------------------------------------------Status screen------------------------------------------>>

    //Main method of painting the status screen
    private void paintStatusScreen(int currentScreen) {
        this.getCharacterStats();
        switch (currentScreen) {
            case STATUS_SCREEN:
                try {
                    g.setColor(WHITE);
                    g.setFont(fontStatus);
                    g.drawImage(menuImages[6], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.VCENTER | Graphics.HCENTER);
                    g.drawImage(menuImages[0], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.VCENTER | Graphics.HCENTER);
                    paintStatus(this.STATUS_SCREEN);
                    paintLevel();
                    paintBar(this.STATUS_SCREEN);
                    paintPlayerImage(currentCharacterCode);
                    paintOverworldMap();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                break;
            case BATTLE_SCREEN:
                calculateBarWidth(true);
                g.setColor(WHITE);
                g.setFont(fontBattle);
                paintStatus(this.BATTLE_SCREEN);
                paintBar(this.BATTLE_SCREEN);
                paintPlayerName(currentCharacterCode);
                break;
        }
    }

    //Paints the player name at battle screen
    private void paintPlayerName(int characterCode) {
        g.setColor(WHITE);
        switch (characterCode) {
            case OverworldCharacter.LYN:
                g.drawString(LYN_LABEL, 0, 0, Graphics.LEFT | Graphics.TOP);
                break;
            case OverworldCharacter.ELIWOOD:
                g.drawString(ELIWOOD_LABEL, 0, 0, Graphics.LEFT | Graphics.TOP);
                break;
            case OverworldCharacter.EIRIK:
                g.drawString(EIRIK_LABEL, 0, 0, Graphics.LEFT | Graphics.TOP);
                break;
        }
    }


    //Creates the images according to the main player
    private void paintPlayerImage(int characterCode ) throws IOException {
        g.setColor(WHITE);
        switch(characterCode) {
            case OverworldCharacter.LYN :
                g.drawString(LYN_LABEL, this.SCREEN_X_FIRST_QUARTER/3, this.SCREEN_Y_FIRST_QUARTER/6, Graphics.LEFT | Graphics.TOP);
                break;
            case OverworldCharacter.ELIWOOD :
                g.drawString(ELIWOOD_LABEL, this.SCREEN_X_FIRST_QUARTER/3, this.SCREEN_Y_FIRST_QUARTER/6, Graphics.LEFT | Graphics.TOP);
                break;
            case OverworldCharacter.EIRIK :
                g.drawString(EIRIK_LABEL, this.SCREEN_X_FIRST_QUARTER/3, this.SCREEN_Y_FIRST_QUARTER/6, Graphics.LEFT | Graphics.TOP);
                break;
            default :
                System.out.println("Wrong character code");
        }
        //g.drawImage(this.playerImages[characterCode], this.SCREEN_X_FIRST_QUARTER/3, this.SCREEN_Y_FIRST_QUARTER/2, Graphics.LEFT | Graphics.TOP);
    }

    /**
     * Sets the current minimap
     * @param newMiniMap
     */
    public void setMiniMap(Image newMiniMap){
        this.miniMap = newMiniMap;
    }

    //Creates the map image according to current scene
    private void paintOverworldMap() throws IOException{
        //MEMORY WASTE
        g.drawImage(miniMap, this.SCREEN_X_CENTER, this.SCREEN_Y_THIRD_QUARTER, Graphics.HCENTER | Graphics.VCENTER);
    }

    //Checks for the priority and calls the respective methods to paint
    private void paintBar(int currentScreen){
        this.setBarColor(playerHP, playerMaxHP);
        this.paintHPBar(currentScreen);
        this.setBarColor(playerMP, playerMaxMP);
        this.paintMPBar(currentScreen);
        if (currentScreen == STATUS_SCREEN) {
            this.paintXPBar();
        }
    }

    //Draws the rectangle of the main player HP
    private void paintHPBar(int currentScreen) {
       switch ( currentScreen ) {
           case STATUS_SCREEN :
               g.fillRect(this.SCREEN_X_CENTER, 2*(SCREEN_Y_FIRST_QUARTER/15), this.barHPWidth, 3);
               break;
           case BATTLE_SCREEN :
               g.fillRect(this.SCREEN_X_SECOND_FIFTH, 7, this.barHPWidth, 3);
               break;
       }
    }

    //Draws the rectangle of the main player MP
    private void paintMPBar(int currentScreen) {
       switch ( currentScreen ) {
           case STATUS_SCREEN :
               g.fillRect(this.SCREEN_X_CENTER, 8*(SCREEN_Y_FIRST_QUARTER/15), this.barMPWidth, 3);
               break;
           case BATTLE_SCREEN :
               g.fillRect(this.SCREEN_X_FOURTH_FIFTH, 7, this.barMPWidth, 3);
               break;
       }
    }

    //Draws the rectangle of the main player XP
    private void paintXPBar(){
        g.setColor(GameDisplay.BLUE);
        g.fillRect(SCREEN_X_CENTER, 14*(SCREEN_Y_FIRST_QUARTER/15), barXPWidth, 3);
    }

    //Calculate the length of the bar
    private void calculateBarWidth(boolean battle) {
        if (battle) {
            barHPWidth = (mainPlayer.getCurrentHealthPoints() * SCREEN_X_FIRST_FIFTH) / mainPlayer.getMaxHealthPoints();
            barMPWidth = (mainPlayer.getCurrentMagicPoints() * SCREEN_X_FIRST_FIFTH) / mainPlayer.getMaxMagicPoints();
            barXPWidth = (mainPlayer.getCurrentXP() * SCREEN_X_FIRST_FIFTH) / mainPlayer.getNextLevelPoints();
        } else {
            barHPWidth = (mainPlayer.getCurrentHealthPoints() * SCREEN_X_FIRST_QUARTER) / mainPlayer.getMaxHealthPoints();
            barMPWidth = (mainPlayer.getCurrentMagicPoints() * SCREEN_X_FIRST_QUARTER) / mainPlayer.getMaxMagicPoints();
            barXPWidth = (mainPlayer.getCurrentXP() * SCREEN_X_FIRST_QUARTER) / mainPlayer.getNextLevelPoints();
        }
    }

    //Calculate the color of the bar
    private void setBarColor(int currentStatusValue, int maximumStatusValue) {
        float interval = maximumStatusValue/3;
        if(currentStatusValue <= interval) {
            g.setColor(RED);
        } else if (currentStatusValue >= 2*interval) {
            g.setColor(GREEN);
        } else {
            g.setColor(YELLOW);
        }
    }

    //Sets the character data to the GameDisplay.
    private void getCharacterStats() {
        if(playerHP != mainPlayer.getCurrentHealthPoints()) {
            playerHP = mainPlayer.getCurrentHealthPoints();
            playerHPLabel = "HP: " + playerHP;
        }
        if(playerMP != mainPlayer.getMaxMagicPoints()) {
            playerMP = mainPlayer.getMaxMagicPoints();
            playerMPLabel = "MP: " + playerMP;
        }
        if(playerXP != mainPlayer.getCurrentXP()) {
            playerXP = mainPlayer.getCurrentXP();
            playerXPLabel = "XP: " + playerXP;
        }
        if(playerLevel != mainPlayer.getCurrentLevel()) {
            playerLevel = mainPlayer.getCurrentLevel();
            playerLevelLabel = "" + playerLevel;
        }
        playerCode = this.adminGame.getPlayer().getCharacterCode();
        playerMaxHP = mainPlayer.getMaxHealthPoints();
        playerMaxMP = mainPlayer.getMaxMagicPoints();
    }

    //Paints the HP, MP  and XP status
    private void paintStatus(int currentScreen) {
        this.paintHP(currentScreen);
        this.paintMP(currentScreen);
        if (currentScreen == STATUS_SCREEN) {
            this.paintXP();
        }
    }

    //Draws the main player HP
    private void paintHP(int currentScreen) {
        switch(currentScreen) {
            case STATUS_SCREEN:
                g.drawString(this.playerHPLabel, this.SCREEN_X_FIRST_QUARTER, 0, Graphics.LEFT | Graphics.TOP);
                break;
            case BATTLE_SCREEN:
                g.drawString(this.playerHPLabel, this.SCREEN_X_FIRST_FIFTH, 0, Graphics.LEFT | Graphics.TOP);
        }
    }

    //Paints the player MP
    private void paintMP(int currentScreen) {
        switch(currentScreen) {
            case STATUS_SCREEN:
                g.drawString(this.playerMPLabel, this.SCREEN_X_FIRST_QUARTER, this.SCREEN_Y_FIRST_QUARTER/3, Graphics.LEFT | Graphics.TOP);
                break;
            case BATTLE_SCREEN:
                g.drawString(this.playerMPLabel, this.SCREEN_X_THIRD_FIFTH, 0, Graphics.LEFT | Graphics.TOP);
                break;
        }
    }

    //Draws the main player XP
    private void paintXP() {
        g.drawString(this.playerXPLabel, SCREEN_X_FIRST_QUARTER, 2*SCREEN_Y_FIRST_QUARTER/3, Graphics.LEFT | Graphics.TOP);
    }

    //Draws the level of main player
    private void paintLevel() {
        g.drawString(levelLabel, SCREEN_X_THIRD_QUARTER, 0, Graphics.LEFT | Graphics.TOP);
        g.drawString(playerLevelLabel, SCREEN_X_THIRD_QUARTER, SCREEN_Y_FIRST_QUARTER/3, Graphics.LEFT | Graphics.TOP);
    }

    /**
     * Paints the game over screen
     */
    public void paintGameOver() {
        adminGame.paint(g);
        g.drawImage(menuImages[0], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.VCENTER | Graphics.HCENTER);
        g.drawImage(menuImages[7], SCREEN_X_CENTER, SCREEN_Y_CENTER, Graphics.VCENTER | Graphics.HCENTER);
    }

    /**
     * Set a game over
     * @param gameOver true if it is a game over
     */
    public void setGameOver(boolean gameOver){
        this.isGameOver = gameOver;
        this.currentScreen = OVERWORLD_SCREEN;
    }

    protected void hideNotify() {
        this.currentScreen = PAUSE_SCREEN;
        super.hideNotify();
    }
    //<<---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->>

}